run' :: MVar AnnexState -> AnnexRead -> Annex a -> IO (a, (AnnexState, AnnexRead))
run' mvar rd a = do
r <- runReaderT (runAnnex a) (mvar, rd)
- `onException` (flush rd)
- flush rd
st <- takeMVar mvar
return (r, (st, rd))
- where
- flush = Keys.flushDbQueue . keysdbhandle
{- Performs an action in the Annex monad from a starting state,
- and throws away the changed state. -}
{- git-annex actions
-
- - Copyright 2010-2020 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2022 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
action,
verifiedAction,
startup,
- shutdown,
+ quiesce,
stopCoProcesses,
) where
import Annex.HashObject
import Annex.CheckIgnore
import Annex.TransferrerPool
+import qualified Database.Keys
import Control.Concurrent.STM
#ifndef mingw32_HOST_OS
return ()
#endif
-{- Cleanup actions. -}
-shutdown :: Bool -> Annex ()
-shutdown nocommit = do
+{- Rn all cleanup actions, save all state, stop all long-running child
+ - processes.
+ -
+ - This can be run repeatedly with other Annex actions run in between,
+ - but usually it is run only once at the end.
+ -
+ - When passed True, avoids making any commits to the git-annex branch,
+ - leaving changes in the journal for later commit.
+ -}
+quiesce :: Bool -> Annex ()
+quiesce nocommit = do
+ cas <- Annex.withState $ \st -> return
+ ( st { Annex.cleanupactions = mempty }
+ , Annex.cleanupactions st
+ )
+ sequence_ (M.elems cas)
saveState nocommit
- sequence_ =<< M.elems <$> Annex.getState Annex.cleanupactions
stopCoProcesses
+ Database.Keys.closeDb
{- Stops all long-running child processes, including git query processes. -}
stopCoProcesses :: Annex ()
saveState :: Bool -> Annex ()
saveState nocommit = doSideAction $ do
Annex.Queue.flush
- Database.Keys.closeDb
+ Database.Keys.flushDb
unless nocommit $
whenM (annexAlwaysCommit <$> Annex.getGitConfig) $
Annex.Branch.commit =<< Annex.Branch.commitMessage
state <- Annex.new
=<< Git.Config.read
=<< Git.Construct.fromPath (toRawFilePath dir)
- Annex.eval state $ a `finally` stopCoProcesses
+ Annex.eval state $ a `finally` quiesce True
{- Creates a new repository, and returns its UUID. -}
initRepo :: Bool -> Bool -> FilePath -> Maybe String -> Maybe StandardGroup -> IO UUID
import Annex.WorkTree
import Git.Command
import qualified Utility.RawFilePath as R
+import Annex.Actions
import Data.Time.Clock
import Data.Char
ood <- Annex.eval state $ do
buildrpms topdir updated
makeinfos updated version
+ quiesce False
syncToArchiveOrg
unless (null ood) $
error $ "Some info files are out of date: " ++ show (map fst ood)
prepRunCommand cmd annexsetter
startup
performCommandAction True cmd seek $
- shutdown $ cmdnocommit cmd
+ quiesce $ cmdnocommit cmd
go (Left norepo) = do
let ingitrepo = \a -> a =<< Git.Config.global
-- Parse command line with full cmdparser first,
import Annex.UUID
import P2P.Address
import P2P.Auth
+import Annex.Action
run :: [String] -> IO ()
run (_remotename:address:[]) = forever $
g <- Annex.gitRepo
conn <- liftIO $ connectPeer g (TorAnnex address port)
runst <- liftIO $ mkRunState Client
- liftIO $ runNetProto runst conn $ auth myuuid authtoken noop >>= \case
+ r <- liftIO $ runNetProto runst conn $ auth myuuid authtoken noop >>= \case
Just _theiruuid -> connect service stdin stdout
Nothing -> giveup $ "authentication failed, perhaps you need to set " ++ p2pAuthTokenEnv
+ quiesce False
+ return r
ifM (getViaTmp rsp DefaultVerify key (AssociatedFile Nothing) go)
( do
logStatus key InfoPresent
- -- forcibly quit after receiving one key,
- -- and shutdown cleanly
- _ <- shutdown True
+ _ <- quiesce True
return True
, return False
)
import Config.Files.AutoStart
import Upgrade
import Annex.Version
+import Annex.Action
import Utility.Android
import Control.Concurrent
Right state -> void $ Annex.eval state $ do
whenM (fromRepo Git.repoIsLocalBare) $
giveup $ d ++ " is a bare git repository, cannot run the webapp in it"
- callCommandAction $
+ r <- callCommandAction $
start' False o
+ quiesce False
+ return r
cannotStartIn :: FilePath -> String -> IO ()
cannotStartIn d reason = warningIO $ "unable to start webapp in repository " ++ d ++ ": " ++ reason
{- Sqlite database of information about Keys
-
- - Copyright 2015-2021 Joey Hess <id@joeyh.name>
+ - Copyright 2015-2022 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
module Database.Keys (
DbHandle,
closeDb,
+ flushDb,
addAssociatedFile,
getAssociatedFiles,
getAssociatedFilesIncluding,
{- Closes the database if it was open. Any writes will be flushed to it.
-
- - This does not normally need to be called; the database will auto-close
- - when the handle is garbage collected. However, this can be used to
- - force a re-read of the database, in case another process has written
- - data to it.
+ - This does not prevent further use of the database; it will be re-opened
+ - as necessary.
-}
closeDb :: Annex ()
closeDb = liftIO . closeDbHandle =<< Annex.getRead Annex.keysdbhandle
+{- Flushes any queued writes to the database. -}
+flushDb :: Annex ()
+flushDb = liftIO . flushDbQueue =<< Annex.getRead Annex.keysdbhandle
+
addAssociatedFile :: Key -> TopFilePath -> Annex ()
addAssociatedFile k f = runWriterIO $ SQL.addAssociatedFile k f
":" ++ show e
Annex.getState Annex.repo
s <- newLocal r
- liftIO $ Annex.eval s $ check `finally` stopCoProcesses
+ liftIO $ Annex.eval s $ check
+ `finally` quiesce True
failedreadlocalconfig = do
unless hasuuid $ case Git.remoteName r of
Annex.Content.lockContentForRemoval key cleanup $ \lock -> do
Annex.Content.removeAnnex lock
cleanup
- Annex.Content.saveState True
, giveup "remote does not have expected annex.uuid value"
)
| Git.repoIsHttp repo = giveup "dropping from http remote not supported"
let checksuccess = liftIO checkio >>= \case
Just err -> giveup err
Nothing -> return True
- res <- logStatusAfter key $ Annex.Content.getViaTmp rsp verify key file $ \dest ->
+ logStatusAfter key $ Annex.Content.getViaTmp rsp verify key file $ \dest ->
metered (Just (combineMeterUpdate meterupdate p)) key bwlimit $ \_ p' ->
copier object (fromRawFilePath dest) key p' checksuccess verify
- Annex.Content.saveState True
- return res
)
unless res $
giveup "failed to send content to remote"
Annex.eval s $ do
Annex.BranchState.disableUpdate
ensureInitialized (pure [])
- a `finally` stopCoProcesses
+ a `finally` quiesce True
data LocalRemoteAnnex = LocalRemoteAnnex Git.Repo (MVar [(Annex.AnnexState, Annex.AnnexRead)])
{- Runs an action from the perspective of a local remote.
-
- The AnnexState is cached for speed and to avoid resource leaks.
- - However, coprocesses are stopped after each call to avoid git
- - processes hanging around on removable media.
+ - However, it is quiesced after each call to avoid git processes
+ - hanging around on removable media.
-
- The remote will be automatically initialized/upgraded first,
- when possible.
go ((st, rd), a') = do
curro <- Annex.getState Annex.output
let act = Annex.run (st { Annex.output = curro }, rd) $
- a' `finally` stopCoProcesses
+ a' `finally` quiesce True
(ret, (st', _rd)) <- liftIO $ act `onException` cache (st, rd)
liftIO $ cache (st', rd)
return ret